package main

import (
	"fmt"
	"go-socks5/pkg/config"
	"go-socks5/pkg/log"
	"go-socks5/server"
	"os"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const Version = "0.0.1"

var (
	cfgFile     string
	showVersion bool
	cfg         config.ServerConfig
)

func init() {
	rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file of socks5")
	rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of socks5")

	cobra.OnInitialize(initConfig)
}

func initConfig() {
	if cfgFile != "" {
		// 使用指定的配置文件
		viper.SetConfigFile(cfgFile)
	} else {
		fmt.Println("use default config")
		// 查找默认配置文件目录
		home, err := os.UserHomeDir()
		if err != nil {
			fmt.Println("Error:", err)
			os.Exit(1)
		}

		// 设置默认配置文件搜索路径
		viper.AddConfigPath(home)
		viper.AddConfigPath(".")
		viper.AddConfigPath("/etc/go-socks5")
		viper.SetConfigName("config")
		viper.SetConfigType("yaml")
	}

	// 读取环境变量
	viper.AutomaticEnv()

	// 读取配置文件
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())

		// 将配置文件中的值绑定到配置结构体
		if err := viper.Unmarshal(&cfg); err != nil {
			fmt.Println("Error parsing config:", err)
			os.Exit(1)
		}
	} else {
		// 配置文件不存在或无法读取时不终止，使用默认值或命令行参数
		if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
			fmt.Println("Error reading config file:", err)
		}
	}
}

var rootCmd = &cobra.Command{
	Use:   "go-socks5",
	Short: "go-socks5 is the proxy server of SOCKS5 protocol",
	RunE: func(cmd *cobra.Command, args []string) error {
		if showVersion {
			fmt.Printf("go-socks5 version %s\n", Version)
			return nil
		}

		// 验证必填字段
		if cfg.BindPort <= 0 || cfg.BindPort > 65535 {
			return fmt.Errorf("invalid bind port: %d, must be between 1-65535", cfg.BindPort)
		}

		// 设置默认值
		if cfg.BindAddr == "" {
			cfg.BindAddr = "0.0.0.0"
		}

		if cfg.Timeout <= 0 {
			cfg.Timeout = 60 // 默认超时时间为60秒
		}

		// 验证认证配置
		if cfg.EnableAuth {
			if cfg.Username == "" || cfg.Password == "" {
				return fmt.Errorf("username and password are required when authentication is enabled")
			}
		}

		// 验证日志配置
		if cfg.Log.Level == "" {
			cfg.Log.Level = "info" // 默认日志级别
		}

		if cfg.Log.To == "" {
			cfg.Log.To = "console" // 默认日志输出到控制台
		}

		if cfg.Log.MaxDays <= 0 {
			cfg.Log.MaxDays = 30 // 默认日志保留30天
		}

		if cfg.Log.DisablePrintColor {
			cfg.Log.DisablePrintColor = true // 默认不启用彩色日志
		}

		// 设置 Dashboard 默认值
		if cfg.Dashboard.Enable && cfg.Dashboard.Port <= 0 {
			cfg.Dashboard.Port = 8080 // 默认 Dashboard 端口
		}

		// 使用完整配置启动服务器
		if err := runServer(&cfg); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		return nil
	},
}

func runServer(cfg *config.ServerConfig) error {
	log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)

	// 创建 SOCKS5 服务器
	s, err := server.NewSocks5Server(cfg)
	if err != nil {
		return err
	}
	log.Infof("socks5 server started on port %d", cfg.BindPort)

	// 如果启用了 Dashboard，启动 Dashboard API 服务器
	if cfg.Dashboard.Enable {
		serverInfo := &server.ServerInfo{
			Version:    Version,
			BindAddr:   cfg.BindAddr,
			BindPort:   cfg.BindPort,
			EnableAuth: cfg.EnableAuth,
			Username:   cfg.Username,
			Password:   cfg.Password,
			LogPath:    cfg.Log.To,
			StartTime:  time.Now(),
		}

		// 创建 Dashboard 服务器，传入配置的用户名和密码
		dashboardServer := server.NewDashboardServer(
			cfg.Dashboard.Port,
			cfg.Dashboard.Username,
			cfg.Dashboard.Password,
			s.ClientManager,
			serverInfo,
		)

		// 启动 Dashboard 服务器（使用 goroutine 避免阻塞主服务器）
		go func() {
			if err := dashboardServer.Start(); err != nil {
				log.Errorf("Dashboard server error: %v", err)
			}
		}()

	}

	// 启动 SOCKS5 服务器
	return s.Run()
}
